package com.ninong.ker.admin.conf;

import com.ninong.ker.common.annotation.log.Log;
import com.ninong.ker.common.auth.SecurityAdmin;
import com.ninong.ker.common.tools.CmdAdminTools;
import com.ninong.ker.common.tools.ThrowableUtil;
import com.ninong.ker.common.user.OnlineUser;
import com.ninong.ker.log.domain.FwLog;
import com.ninong.ker.log.service.FwLogService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Component
@Aspect
@Slf4j
public class LogAspect {

    @Reference(check = false,version = "1.0.0")
    private FwLogService logService;

    ThreadLocal<Long> currentTime = new ThreadLocal<>();

    @Autowired
    private SecurityAdmin securityAdmin;

    /**
     * 配置切入点
     */
    @Pointcut("@annotation(com.ninong.ker.common.annotation.log.Log)")
    public void logPointcut() {
        // 该方法无方法体,主要为了让同类中其他方法使用此切入点
    }

    /**
     * 配置环绕通知,使用在方法logPointcut()上注册的切入点
     *
     * @param joinPoint join point for advice
     */
    @Around("logPointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result;
        currentTime.set(System.currentTimeMillis());
        result = joinPoint.proceed();
        FwLog log = new FwLog();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Log aopLog = method.getAnnotation(Log.class);
        // 描述
        if (ObjectUtils.isNotEmpty(aopLog)) {
            log.setDescription(aopLog.value());
        }
        // 方法路径
        String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()";
        log.setMethod(methodName);
        HttpServletRequest request = CmdAdminTools.getHttpServletRequest();
        log.setBrowser(CmdAdminTools.getBrowser(request));
        log.setTime(System.currentTimeMillis() - currentTime.get());
//        log.setParams(getParameter(method, joinPoint.getArgs()));
        String token = securityAdmin.getToken(request);
        if(StringUtils.isNotEmpty(token)){
            if(securityAdmin.validateToken(token)) {
                OnlineUser user = securityAdmin.currentUser(token);
                log.setUsername(user.getUserName());
            }
        }
        currentTime.remove();
        log.setLogType("INFO");
        log.setRequestIp(CmdAdminTools.getIp(request));
//        logService.insert(log);
        return result;
    }

    /**
     * 配置异常通知
     *
     * @param joinPoint join point for advice
     * @param e exception
     */
    @AfterThrowing(pointcut = "execution(* com.ninong.ker.admin.service.impl.*.*(..))", throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
        FwLog log = new FwLog();
        // 方法路径
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()";
        log.setMethod(methodName);
        log.setLogType("ERROR");
//        log.setTime(System.currentTimeMillis() - currentTime.get());
        currentTime.remove();
        log.setExceptionDetail(ThrowableUtil.getStackTrace(e));
        HttpServletRequest request = CmdAdminTools.getHttpServletRequest();
        log.setRequestIp(CmdAdminTools.getIp(request));
        String token = securityAdmin.getToken(request);
        if(StringUtils.isNotEmpty(token)){
            OnlineUser user = securityAdmin.currentUser(token);
            log.setUsername(user.getUserName());
        }
//        logService.insert(log);
    }
}
